/*********************\
* Author:Dzlua
* QQ:505544956
* Time:2017/03/22
\**********************/
#include "SDLuaMgr.h"
#include "LuaRegister.h"
#include "Base/LuaHelper.h"

namespace DuiLib {

SDLuaMgr::SDLuaMgr() : m_bCreatedLua(false), m_lua(nullptr)
{}

SDLuaMgr::~SDLuaMgr()
{}

void SDLuaMgr::Init(LuaState* luastate /*= nullptr*/)
{
    m_lua = luastate;
    if (!m_lua) {
        m_lua = LuaState::Create(true);
        m_bCreatedLua = true;
    }

    m_lua->OpenLibs();
    this->Register();
}

void SDLuaMgr::Quit()
{
    this->UnRegister();

    if (m_bCreatedLua && m_lua){
        LuaState::Destroy(m_lua);
        m_lua = 0;
        m_bCreatedLua = false;
    }
}

//for return void
void* SDLuaMgr::DoEventVoid(void* key, LPCSTR name, void* data1, void* data2)
{
    LuaObject obj = LuaHelperNS::GetEventFromObjs(m_lua, key, name);
    if (!obj.IsFunction()) return 0;
    LuaFunction<void> evtFun(obj);
    evtFun(LuaHelperNS::GetFromObjs(m_lua, key), (int)data1, (int)data2);
    return 0;
}

//for return int
void* SDLuaMgr::DoEventInt(void* key, LPCSTR name, void* data1, void* data2)
{
    LuaObject obj = LuaHelperNS::GetEventFromObjs(m_lua, key, name);
    if (!obj.IsFunction()) return 0;
    LuaFunction<int> evtFun(obj);
    return (void*)evtFun(LuaHelperNS::GetFromObjs(m_lua, key), (int)data1, (int)data2);
}

//for return cobj
void* SDLuaMgr::DoEventCObj(void* key, LPCSTR name, void* data1, void* data2)
{
    LuaObject obj = LuaHelperNS::GetEventFromObjs(m_lua, key, name);
    if (!obj.IsFunction()) return 0;
    LuaFunction<LuaObject> evtFun(obj);
    LuaObject retObj = evtFun(LuaHelperNS::GetFromObjs(m_lua, key), (int)data1, (int)data2);
    return LuaHelperNS::GetCObjectData(retObj);
}

//for notify
void* SDLuaMgr::DoEventNotify(SDWindow* wnd, void* key, LPCSTR name, void* data1, void* data2)
{
    LuaObject obj = LuaHelperNS::GetEventFromObjs(m_lua, key, name);
    if (!obj.IsFunction()) return 0;
    LuaFunction<void> evtFun(obj);
    evtFun(LuaHelperNS::GetFromObjs(m_lua, wnd),
            LuaHelperNS::GetFromObjs(m_lua, key),
            (int)data1, (int)data2);
    return 0;
}

//SDLuaScript::
void* SDLuaMgr::HandleMessage(SDWindow* wnd, SPDUI_MSG msg, void* data1 /*= 0*/, void* data2 /*= 0*/)
{
    //cause only English,ansi equals to utf8.
    if (!wnd) return 0;
    switch (msg) {
    case SPDUI_MSG_ON_CREATE: return DoEventVoid(wnd, "OnCreate", data1, data2);
    case SPDUI_MSG_ON_ZOOMED: return DoEventVoid(wnd, "OnZoomed", data1, data2);
    case SPDUI_MSG_ON_NOTIFY: {
        TNotifyUI* nf = (TNotifyUI*)data1;
        return DoEventNotify(wnd, nf->pSender,
                SDConvert::TToU(nf->sType.GetData()).c_str(),
                (void*)nf->wParam, (void*)nf->lParam);
    }
    case SPDUI_MSG_ON_CREATECONTROL: {
        LuaObject obj = LuaHelperNS::GetEventFromObjs(m_lua, wnd, "OnCreateControl");
        if (!obj.IsFunction()) return 0;
        LuaFunction<LuaObject> evtFun(obj);
        SDString name = SDConvert::TToU((LPCTSTR)data1);
        LuaObject retObj = evtFun(LuaHelperNS::GetFromObjs(m_lua, wnd), name.c_str());
        return LuaHelperNS::GetCObjectData(retObj);
    }
    //--------------//
    case SPDUI_MSG_ON_CLOSE: return DoEventInt(wnd, "OnClose", data1, data2);
    case SPDUI_MSG_ON_DESTROY: return DoEventInt(wnd, "OnDestroy", data1, data2);
    case SPDUI_MSG_ON_KEYDOWN: return DoEventInt(wnd, "OnKeyDown", data1, data2);
    case SPDUI_MSG_ON_KEUP: return DoEventInt(wnd, "OnKeyUp", data1, data2);
    case SPDUI_MSG_ON_SETFOCUS: return DoEventInt(wnd, "OnSetFocus", data1, data2);
    case SPDUI_MSG_ON_KILLFOCUS: return DoEventInt(wnd, "OnKillFocus", data1, data2);
    default : break; 
    }
    return 0;
}

LuaObject SDLuaMgr::AddObj(const char* key, void* data)
{
    LuaObject obj;
    //metatable
    LuaObject meta = LuaHelperNS::GetFromMetas(m_lua, key);
    if (!meta.IsTable()) return obj;
    if (!meta[SDLUA_NEWCOBJ].IsFunction()) return obj;
    
    //new a cluaobj
    LuaFunction<void*> funNewObj(meta[SDLUA_NEWCOBJ]);
    LuaClassBase *pCObj = (LuaClassBase*)funNewObj(data);
    if (!pCObj) return obj;
    
    //create a table and add to saved Luaclss objects.
    obj = LuaHelperNS::AddToObjs(m_lua, data);
    if (obj.IsNil()) {
        pCObj->Release();
        return obj;
    }
    //save CObj.
    LuaHelperNS::SetCObject(obj, pCObj);
    //set metatable.
    obj.SetMetaTable(meta);
    return obj;
}

void SDLuaMgr::RemoveObj(void* data)
{
    //get the cluaobj.
    LuaObject obj = LuaHelperNS::GetFromObjs(m_lua, data);
    //get the CObj.
    LuaClassBase *pCObj = LuaHelperNS::GetCObject(obj);
    if (pCObj) pCObj->Release();
    LuaHelperNS::RemoveFromObjs(m_lua, data);
}

bool SDLuaMgr::DoFile(const char* file)
{
    if (!file) return false;
    if (0 == m_lua->DoFile(file)) return true;
    LuaStack args(m_lua);
    if (args[1].IsString()){
        SDPtr->SetError(SDConvert::UToT(
                args[1].GetString() ));
    }
    return false;
}

LuaState* SDLuaMgr::GetState() const
{
    return m_lua;
}

void SDLuaMgr::Register()
{
    RegisterAll(m_lua);
}

void SDLuaMgr::UnRegister()
{
    UnRegisterAll(m_lua);
}

}